#pragma once

#include "StickyTweetsStatus.h"

#define IoBufferLength 4096
#define InvalidDownloadSize (DWORD)-1

/*!
 * \brief The callback will get one of two context types
 */
typedef enum InternetContextTypeE
{
  IctMain,
  IctRequest
} InternetContextType;

/*!
 * \brief Determines what we intend to send/get back
 */
typedef enum RequestTypeE
{
  RtUnknown,
  RtCurrentTimeline,
  RtMentions,
  RtDirect,
  RtSentDirect,
  RtUserTimeline,
  RtSearch
} RequestType;

/*!
 * \brief Session and connection handles
 */
class MainContext
{
public:
  InternetContextType ContextType; //< Main
  HINTERNET Session; //< Internet session handle
  HINTERNET Connection; //< Internet connection handle

public:
  MainContext();
  ~MainContext();

  StickyTweetsStatus Open(const CString& screenName, const CString& password, INTERNET_STATUS_CALLBACK callback);

  StickyTweetsStatus OpenSearch(INTERNET_STATUS_CALLBACK callback);

  /*!
   * \brief Don't reset the callback, just verify that the connection is still valid
   */
  StickyTweetsStatus Verify(const CString& screenName, const CString& password);

  StickyTweetsStatus Close(VOID);

private:
  INTERNET_STATUS_CALLBACK _callback;
};

/*!
 * \brief Everything else about a request including IO
 */
class RequestContext
{
public:
  InternetContextType ContextType; //< Request
  MainContext* Main; //< Pointer to MainContext
  HINTERNET Request; //< Current request handle
  RequestType Type; //< Type of request
  CString Resource; //< The HTTP resource string, part of which is Query
  CString Query; //< sinceId, screenName or query depending on RequestType
  StickyTweetsStatus Status; //< Final status of request
  BYTE OutputBuffer[IoBufferLength]; //< Buffer for Internet reads
  CString OutputXml; //< Output
  DWORD DownloadedSize; //< Total downloaded so far
  DWORD ReadSize; //< Amount read this pass
  DWORD WrittenSize; //< Amount written to buffer
  DWORD ReadOffset; //< Offset in read buffer
  DWORD WriteOffset; //< Offset in write buffer
  LONG PendingWrites; //< Waiting on buffer write
  BOOL ReceiveDone; //< Done receiving flag
  CRITICAL_SECTION CriticalSection; //< Critical section

public:
  RequestContext(MainContext* pMainContext);
  ~RequestContext();

  StickyTweetsStatus SendRequest(RequestType type, CString resource, CString query = L"");
};

/*!
 * \brief Required for Asynchronous IO operations
 */
typedef struct IoBufferT
{
  OVERLAPPED OverlappedIo;
  RequestContext* Request;
  BYTE Buffer[IoBufferLength];
} IoBuffer;

